package com.newfiber.workflow.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.newfiber.common.core.annotation.WorkflowFileWrapper;
import com.newfiber.common.core.enums.EBoolean;
import com.newfiber.common.core.web.page.PageResult;
import com.newfiber.workflow.config.diagram.CustomProcessDiagramGenerator;
import com.newfiber.workflow.config.diagram.FlowableWorkflowConstants;
import com.newfiber.workflow.entity.WorkflowHistoricActivity;
import com.newfiber.workflow.entity.WorkflowUser;
import com.newfiber.workflow.entity.response.WorkflowCountStatics;
import com.newfiber.workflow.entity.response.WorkflowModelNextTaskResponse;
import com.newfiber.workflow.enums.EConstantValue;
import com.newfiber.workflow.enums.IWorkflowActivityType.EventActivity;
import com.newfiber.workflow.enums.IWorkflowActivityType.TaskActivity;
import com.newfiber.workflow.service.FlowableModelService;
import com.newfiber.workflow.service.FlowableProcessService;
import com.newfiber.workflow.service.FlowableUserService;
import com.newfiber.workflow.support.IWorkflowCallback;
import com.newfiber.workflow.support.WorkflowDefinitionAccessor;
import com.newfiber.workflow.support.request.WorkflowPageRequest;
import com.newfiber.workflow.support.request.WorkflowStartRequest;
import com.newfiber.workflow.support.request.WorkflowSubmitRequest;
import com.newfiber.workflow.support.request.check.INextTaskApproveUserCheck;
import com.newfiber.workflow.utils.NotificationService;
import java.awt.Color;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.EndEvent;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.HistoryService;
import org.flowable.engine.IdentityService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricActivityInstanceQuery;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.engine.task.Comment;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.idm.api.User;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskInfo;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.api.history.HistoricTaskInstanceQuery;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

@Slf4j
@Service
@SuppressWarnings(value = {"unchecked", "rawtypes"})
public class FlowableProcessServiceImpl implements FlowableProcessService {

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private TaskService taskService;

    @Resource
    private HistoryService historyService;

    @Resource
    private IdentityService identityService;

    @Resource
    private NotificationService notificationService;

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private WorkflowDefinitionAccessor workflowDefinitionAccessor;

    @Resource
    private FlowableUserService flowableUserService;

    @Resource
    private FlowableModelService flowableModelService;

    @Override
    public String startWorkflow(IWorkflowCallback<?> callback, Object businessKey) {
        return startWorkflow(callback, businessKey, new HashMap<>());
    }

    @Override
    public String startWorkflow(IWorkflowCallback<?> workflowCallback, Object businessKey, WorkflowStartRequest startReq) {
        Map<String, Object> variables = new HashMap<>();
        if (null != startReq && StringUtils.isNotBlank(startReq.getNextTaskApproveUserId())) {
            variables.put(EConstantValue.ApproveUserIdField.getValue(), startReq.getNextTaskApproveUserId());
        }
        if (null != startReq && StringUtils.isNotBlank(startReq.getNextTaskApproveRoleId())) {
            variables.put(EConstantValue.ApproveRoleIdField.getValue(), startReq.getNextTaskApproveRoleId());
        }
        if (null != startReq && !CollectionUtils.isEmpty(startReq.getNextTaskApproveUserIdList())) {
            variables.put(EConstantValue.ApproveUserIdListField.getValue(), startReq.getNextTaskApproveUserIdList());
        }
        if (null != startReq && !CollectionUtils.isEmpty(startReq.getNotificationTemplateArgs())) {
            variables.put(EConstantValue.NotificationTemplateArgs.getValue(), startReq.getNotificationTemplateArgs());
        }
        return startWorkflow(workflowCallback, businessKey, variables);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String startWorkflow(IWorkflowCallback<?> callback, Object businessKey, Map<String, Object> variables) {
        variables.putIfAbsent(EConstantValue.IWorkflowCallback.getValue(), callback.getClass().getName());
        variables.putIfAbsent(EConstantValue.ApproveResultField.getValue(), EBoolean.True.getBoolString());

        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(callback.getWorkflowDefinition().getWorkflowKey(),
                businessKey.toString(), variables);

        List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).list();

        if (!CollectionUtils.isEmpty(taskList)) {
            callback.refreshStatus(businessKey, taskList.get(0).getTaskDefinitionKey());
            callback.refreshWorkflowInstanceId(businessKey, processInstance.getProcessInstanceId());
        }

        return processInstance.getProcessInstanceId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String submitWorkflow(IWorkflowCallback<?> callback, Object businessKey, WorkflowSubmitRequest submitReq) {
        User user = identityService.createUserQuery().userId(submitReq.getSubmitUserId()).singleResult();
        if (null == user) {
            throw new FlowableException(String.format("用户【%s】不存在", submitReq.getSubmitUserId()));
        }

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(
                businessKey.toString(), callback.getWorkflowDefinition().getWorkflowKey()).singleResult();
        if (null == processInstance) {
            throw new FlowableException(String.format("业务编号【%s】在工作流【%s】中不存在可执行实例",
                    businessKey.toString(), callback.getWorkflowDefinition().getWorkflowName()));
        }

        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).
                taskCandidateOrAssigned(submitReq.getSubmitUserId()).singleResult();
        if (null == task) {
            throw new FlowableException(String.format("用户【%s】在工作流【%s】的业务编号【%s】中不存在可执行任务",
                    user.getFirstName(), callback.getWorkflowDefinition().getWorkflowName(), businessKey.toString()));
        }

        // 下一节点审核人填写检查
        nextTaskApproveUserCheck(callback, submitReq, task);

        // 更新驳回来源状态
	    if(EBoolean.False.getBoolString().equals(submitReq.getApproveResult())){
		    callback.refreshRefuseFromStatus(businessKey, task.getTaskDefinitionKey());
	    }else{
		    callback.refreshRefuseFromStatus(businessKey, "");
	    }

	    // 任务本地变量
        Map<String, Object> variables = new HashMap<>(1);
        variables.put(EConstantValue.ApproveResultField.getValue(), submitReq.getApproveResult());
        Map<String, Object> transientVariables = new HashMap<>();
        if (StringUtils.isNotBlank(submitReq.getNextTaskApproveUserId())) {
            transientVariables.put(EConstantValue.ApproveUserIdField.getValue(), submitReq.getNextTaskApproveUserId());
        }
        if (!CollectionUtils.isEmpty(submitReq.getNextTaskApproveUserIdList())) {
            transientVariables.put(EConstantValue.ApproveUserIdListField.getValue(), submitReq.getNextTaskApproveUserIdList());
        }
        if (StringUtils.isNotBlank(submitReq.getNextTaskApproveRoleId())) {
            transientVariables.put(EConstantValue.ApproveRoleIdField.getValue(), submitReq.getNextTaskApproveRoleId());
        }
        if (!CollectionUtils.isEmpty(submitReq.getNotificationTemplateArgs())) {
            transientVariables.put(EConstantValue.NotificationTemplateArgs.getValue(), submitReq.getNotificationTemplateArgs());
        }

        // 认领并完成任务
        if (StringUtils.isNotBlank(submitReq.getApproveComment())) {
            taskService.addComment(task.getId(), task.getProcessInstanceId(), submitReq.getApproveComment());
        }
        taskService.claim(task.getId(), submitReq.getSubmitUserId());
        taskService.complete(task.getId(), variables, transientVariables);

        // 更新状态
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).list();
        if (!CollectionUtils.isEmpty(taskList)) {
            Set<String> taskDefinitionKeySet = taskList.stream().map(TaskInfo::getTaskDefinitionKey).collect(Collectors.toSet());
            if (taskDefinitionKeySet.size() == 1) {
                callback.refreshStatus(businessKey, taskDefinitionKeySet.iterator().next());
            }
        }

        return businessKey.toString();
    }

	@Override
	public boolean abortWorkflow(IWorkflowCallback<?> callback, Object businessKey) {
		ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(businessKey.toString()).singleResult();
		if (processInstance != null) {
			FlowElement endFlowElement = findEndFlowElement(processInstance.getProcessDefinitionId());
			if(null == endFlowElement){
				log.info("流程「{}」不存在结束节点", callback.getWorkflowDefinition().getWorkflowKey());
				return false;
			}

			List<Execution> executions = runtimeService.createExecutionQuery().parentId(processInstance.getId()).list();
			List<String> executionIds = executions.stream().map(Execution::getId).collect(Collectors.toList());
			runtimeService.createChangeActivityStateBuilder().moveExecutionsToSingleActivityId(executionIds, endFlowElement.getId()).changeState();

			log.info("业务「{} - {}」终止成功", callback.getWorkflowDefinition().getWorkflowKey(), businessKey);
			return true;
		}else {
			log.info("业务「{} - {}」不存在工作流", callback.getWorkflowDefinition().getWorkflowKey(), businessKey);
			return false;
		}
	}

	public FlowElement findEndFlowElement(String processDefId) {
		org.flowable.bpmn.model.Process mainProcess = repositoryService.getBpmnModel(processDefId).getMainProcess();
		Collection<FlowElement> list = mainProcess.getFlowElements();
		if (CollectionUtils.isEmpty(list)) {
			return null;
		}
		List<FlowElement> endEventList = list.stream().filter(t -> t instanceof EndEvent).collect(Collectors.toList());
		if(CollectionUtils.isEmpty(endEventList)){
			return null;
		}else{
			return endEventList.get(0);
		}
	}

	private void nextTaskApproveUserCheck(IWorkflowCallback<?> callback, WorkflowSubmitRequest submitReq, Task task) {
        if (null != callback.getNextTaskApproveUserCheck() && callback.getNextTaskApproveUserCheck().length > 0) {
            for (INextTaskApproveUserCheck nextTaskApproveUserCheck : callback.getNextTaskApproveUserCheck()) {
                if (task.getTaskDefinitionKey().equals(nextTaskApproveUserCheck.getTaskKey())
                        && nextTaskApproveUserCheck.getApproveResult().equals(submitReq.getApproveResult())) {
                    switch (nextTaskApproveUserCheck.getCheckType()) {
                        case User:
                            if (StringUtils.isBlank(submitReq.getNextTaskApproveUserId())) {
                                throw new FlowableException(nextTaskApproveUserCheck.getWarnMessage());
                            }
                            break;
                        case Users:
                            if (CollectionUtil.isEmpty(submitReq.getNextTaskApproveUserIdList())) {
                                throw new FlowableException(nextTaskApproveUserCheck.getWarnMessage());
                            }
                            break;
                        case Role:
                            if (StringUtils.isBlank(submitReq.getNextTaskApproveRoleId())) {
                                throw new FlowableException(nextTaskApproveUserCheck.getWarnMessage());
                            }
                            break;
                        default:
                            break;
                    }
                }
            }
        }
    }

    @Override
    public boolean sendEmailNotification(String email, String content) {
        boolean result;
        if (StringUtils.isBlank(email) || StringUtils.isBlank(content)) {
            result = false;
        } else {
            result = notificationService.sendSimpleMail(email, EConstantValue.EmailNotificationSubject.getValue(), content);
        }
        log.info("邮件发送{} | 邮箱：{} | 内容：{}", result ? "成功" : "失败", email, content);
        return result;
    }

    @Override
    public boolean sendSmsNotification(String mobile, String smsSign, String smsTemplateCode, List<String> templateArgs) {
        boolean result;
        if (StringUtils.isBlank(mobile) || StringUtils.isBlank(smsSign) || StringUtils.isBlank(smsTemplateCode)) {
            result = false;
        } else {
            result = notificationService.sendTencentSms(mobile, smsSign, smsTemplateCode, templateArgs);
        }
        log.info("短信发送{} | 手机号：{} | 模板编号：{}", result ? "成功" : "失败", mobile, smsTemplateCode);
        return result;
    }

    @Override
    public List<String> listTodoBusinessKeyByUser(String workflowKey, String taskKey, Object userId) {
        TaskQuery taskQuery = wrapperTaskQuery(userId, null, workflowKey, taskKey);
        List<Task> taskList = taskQuery.list();
        return listTaskBusinessKey(taskList);
    }

    @Override
    public List<String> listTodoBusinessProcessInstanceIdByUser(String workflowKey, String taskKey, Object userId) {
        TaskQuery taskQuery = wrapperTaskQuery(userId, null, workflowKey, taskKey);
        List<Task> taskList = taskQuery.list();
        return taskList.stream().map(TaskInfo::getProcessInstanceId).distinct().collect(Collectors.toList());
    }

    @Override
    public List<String> listTaskDoneBusinessKeyByUser(String workflowKey, String taskKey, Object userId) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = wrapperHistoryTaskQuery(workflowKey, taskKey, userId);
        List<HistoricTaskInstance> taskList = historicTaskInstanceQuery.list();
        return listHistoryTaskBusinessKey(taskList);
    }

    @Override
    public List<String> listTaskDoneBusinessProcessInstanceIdByUser(String workflowKey, String taskKey, Object userId) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = wrapperHistoryTaskQuery(workflowKey, taskKey, userId);
        List<HistoricTaskInstance> taskList = historicTaskInstanceQuery.list();
        return taskList.stream().map(TaskInfo::getProcessInstanceId).distinct().collect(Collectors.toList());
    }

    @Override
    public List<String> listInvolvedBusinessKeyByUser(String workflowKey, String taskKey, Object userId) {
        List<String> todoBusinessKey = listTodoBusinessKeyByUser(workflowKey, taskKey, userId);
        List<String> doneBusinessKey = listTaskDoneBusinessKeyByUser(workflowKey, taskKey, userId);
        todoBusinessKey.addAll(doneBusinessKey);
        return new ArrayList<>(new HashSet<>(todoBusinessKey));
    }

    @Override
    public List<String> listInvolvedBusinessProcessInstanceIdByUser(String workflowKey, String taskKey, Object userId) {
        List<String> todoBusinessProcessInstanceId = listTodoBusinessProcessInstanceIdByUser(workflowKey, taskKey, userId);
        List<String> doneBusinessProcessInstanceId = listTaskDoneBusinessProcessInstanceIdByUser(workflowKey, taskKey, userId);
        todoBusinessProcessInstanceId.addAll(doneBusinessProcessInstanceId);
        return new ArrayList<>(new HashSet<>(todoBusinessProcessInstanceId));
    }

    @Override
    public List<String> listInvolvedBusinessProcessInstanceIdByUser(IWorkflowCallback<?> callback, String taskKey, Object userId) {
        return listInvolvedBusinessProcessInstanceIdByUser(callback.getWorkflowDefinition().getWorkflowKey(), taskKey, userId);
    }

    @Override
    public List<String> listTodoBusinessKeyByUser(IWorkflowCallback<?> callback, String taskKey, Object userId) {
        return listTodoBusinessKeyByUser(callback.getWorkflowDefinition().getWorkflowKey(), taskKey, userId);
    }

    @Override
    public List<String> listTodoBusinessProcessInstanceIdByUser(IWorkflowCallback<?> callback, String taskKey, Object userId) {
        return listTodoBusinessProcessInstanceIdByUser(callback.getWorkflowDefinition().getWorkflowKey(), taskKey, userId);
    }

    @Override
    public List<String> listTaskDoneBusinessKeyByUser(IWorkflowCallback<?> callback, String taskKey, Object userId) {
        return listTaskDoneBusinessKeyByUser(callback.getWorkflowDefinition().getWorkflowKey(), taskKey, userId);
    }

    @Override
    public List<String> listTaskDoneBusinessProcessInstanceIdByUser(IWorkflowCallback<?> callback, String taskKey, Object userId) {
        return listTaskDoneBusinessProcessInstanceIdByUser(callback.getWorkflowDefinition().getWorkflowKey(), taskKey, userId);
    }

    @Override
    public List<String> listInvolvedBusinessKeyByUser(IWorkflowCallback<?> callback, String taskKey, Object userId) {
        return listInvolvedBusinessKeyByUser(callback.getWorkflowDefinition().getWorkflowKey(), taskKey, userId);
    }

    @Override
    public List<String> listTodoBusinessKey(String workflowKey, String taskKey, Object groupId, Object userId) {
        TaskQuery taskQuery = wrapperTaskQuery(userId, groupId, workflowKey, taskKey);
        List<Task> taskList = taskQuery.list();
        return listTaskBusinessKey(taskList);
    }

    @Override
    public List<WorkflowUser> listTodoBusinessExecutor(String workflowKey, Object businessKey) {

        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(
                businessKey.toString(), workflowKey).singleResult();
        if (null == processInstance) {
            return Collections.emptyList();
        }

        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult();

        if (null == task) {
            return Collections.emptyList();
        }

        List<IdentityLink> identityLinkList = taskService.getIdentityLinksForTask(task.getId());
        if (!CollectionUtils.isEmpty(identityLinkList)) {
            List<User> userList = new ArrayList<>();
            for (IdentityLink identityLink : identityLinkList) {
                if (StringUtils.isNotBlank(identityLink.getUserId())) {
                    userList.add(identityService.createUserQuery().userId(identityLink.getUserId()).singleResult());
                }
                if (StringUtils.isNotBlank(identityLink.getGroupId())) {
                    List<User> groupUserList = identityService.createUserQuery().memberOfGroup(identityLink.getGroupId()).list();
                    userList.addAll(groupUserList);
                }
            }
            return WorkflowUser.build(userList);
        }

        return Collections.emptyList();
    }

    @Override
    public PageResult<String> pageTodoBusinessKey(String workflowKey, String taskKey, Object groupId, Object userId, WorkflowPageRequest workflowPageRequest) {
        TaskQuery taskQuery = wrapperTaskQuery(userId, groupId, workflowKey, taskKey);
        List<Task> taskList = taskQuery.listPage(workflowPageRequest.pageStart(), workflowPageRequest.getPageSize());
        List<String> businessKeyList = listTaskBusinessKey(taskList);
        return new PageResult(businessKeyList, taskQuery.count());
    }

    @Override
    public PageResult<String> pageDoneBusinessKeyByUser(String workflowKey, String taskKey, Object userId, WorkflowPageRequest workflowPageRequest) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = wrapperHistoryTaskQuery(workflowKey, taskKey, userId);
        historicTaskInstanceQuery.listPage(workflowPageRequest.pageStart(), workflowPageRequest.getPageSize());

        List<HistoricTaskInstance> taskList = historicTaskInstanceQuery.list();
        List<String> strings = listHistoryTaskBusinessKey(taskList);
        return new PageResult(strings, historicTaskInstanceQuery.count());
    }

    @Override
    public PageResult<String> pageTodoBusinessKeyByUser(String workflowKey, String taskKey, Object userId, WorkflowPageRequest workflowPageRequest) {
        TaskQuery taskQuery = wrapperTaskQuery(userId, null, workflowKey, taskKey);
        List<Task> taskList = taskQuery.listPage(workflowPageRequest.pageStart(), workflowPageRequest.getPageSize());
        List<String> businessKeyList = listTaskBusinessKey(taskList);
        return new PageResult(businessKeyList, taskQuery.count());
    }

    @Override
    @WorkflowFileWrapper
    public List<WorkflowHistoricActivity> listHistoricActivity(String workflowKey, Object businessKey, String workflowUserId, String status, String fileRefFieldPattern) {
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processDefinitionKey(workflowKey)
                .processInstanceBusinessKey(businessKey.toString()).singleResult();
        if (null == historicProcessInstance) {
            throw new FlowableException(String.format("业务编号【%s】不存在工作流【%s】", businessKey.toString(), workflowKey));
        }

        HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(historicProcessInstance.getId()).orderByHistoricActivityInstanceStartTime().asc();
        if (StringUtils.isNotBlank(workflowUserId)) {
            historicActivityInstanceQuery.taskAssignee(workflowUserId);
        }
        if (StringUtils.isNotBlank(status)) {
            historicActivityInstanceQuery.activityId(status);
        }

        List<HistoricActivityInstance> historicActivityInstanceList = historicActivityInstanceQuery.list();

        // 过滤状态
        historicActivityInstanceList = historicActivityInstanceList.stream().filter(t ->
	        t.getActivityType().contains(EventActivity.Event.getTypeKey()) ||
		        t.getActivityType().contains(TaskActivity.Task.getTypeKey())).collect(Collectors.toList());

        // 过滤执行人
	    historicActivityInstanceList = historicActivityInstanceList.stream().filter(t ->
		    StringUtils.isNotBlank(t.getAssignee()) && NumberUtil.isNumber(t.getAssignee())).collect(Collectors.toList());

	    // 过滤已执行
	    historicActivityInstanceList = historicActivityInstanceList.stream().filter(t ->
		    null != t.getEndTime()).collect(Collectors.toList());

	    // 去掉没有任务名称的
	    historicActivityInstanceList = historicActivityInstanceList.stream().filter(t ->
		    StringUtils.isNotBlank(t.getActivityName())).collect(Collectors.toList());

        List<WorkflowHistoricActivity> workflowHistoricActivityList = new ArrayList<>();
        for (HistoricActivityInstance historicActivityInstance : historicActivityInstanceList) {
            String comment = null;
            String displayName = null;
            String userGroups = null;
            if (StringUtils.isNotBlank(historicActivityInstance.getTaskId())) {
                List<Comment> commentList = taskService.getTaskComments(historicActivityInstance.getTaskId());
                if (commentList.size() > 0) {
                    comment = commentList.get(0).getFullMessage();
                }
                WorkflowUser workflowUser = flowableUserService.getUser(historicActivityInstance.getAssignee());
                if (null != workflowUser) {
                    displayName = workflowUser.getFirstName();
                    userGroups = workflowUser.getUserGroups();
                }
            }

            workflowHistoricActivityList.add(WorkflowHistoricActivity.build(businessKey, fileRefFieldPattern, historicActivityInstance, comment, displayName, userGroups));
        }

        return workflowHistoricActivityList;
    }

    @Override
    public String getNextHistoricAssignee(String workflowKey, Object businessKey, String currentTask, String conditionExpression) {
        WorkflowModelNextTaskResponse workflowModelNextTaskResponse = flowableModelService.nextTasks(workflowKey, currentTask, conditionExpression);
        if (null == workflowModelNextTaskResponse) {
            return null;
        }
        List<WorkflowHistoricActivity> workflowHistoricActivityList = listHistoricActivity(workflowKey, businessKey, null, null, null);
        if (CollectionUtils.isEmpty(workflowHistoricActivityList)) {
            return null;
        }
        Optional<WorkflowHistoricActivity> workflowHistoricActivityOptional = workflowHistoricActivityList.stream().filter(t -> t.getActivityId().equals(workflowModelNextTaskResponse.getNextTaskKey())).findFirst();
        return workflowHistoricActivityOptional.map(WorkflowHistoricActivity::getAssignee).orElse(null);
    }

    @Override
    public Object workflowCountStatics(String workflowKey, Object userId, String taskKey, String queryField, String queryFieldValue) {

	    String workflowInstanceFieldName = workflowDefinitionAccessor.getWorkflowInstanceFieldName(workflowKey);

	    // 业务数据编号
        List<Object> businessDataList = getBusinessDataByWorkflowKey(workflowKey, workflowInstanceFieldName, queryField, queryFieldValue);
        if (CollectionUtils.isEmpty(businessDataList)) {
            return WorkflowCountStatics.zero();
        }

        // 代办、已办的业务编号
        List<String> todoBusinessProcessInstanceId = listTodoBusinessProcessInstanceIdByUser(workflowKey, taskKey, userId);
        List<String> doneBusinessProcessInstanceId = listTaskDoneBusinessProcessInstanceIdByUser(workflowKey, taskKey, userId);

        // 进行数据过滤
	    if(StringUtils.isBlank(queryField) && StringUtils.isBlank(queryFieldValue)){
		    List<String> businessProcessInstanceIdList = businessDataList.stream().map(t ->
                ReflectUtil.getFieldValue(t, StrUtil.toCamelCase(workflowInstanceFieldName)).toString()).collect(Collectors.toList());

		    todoBusinessProcessInstanceId = businessProcessInstanceIdList.stream().filter(todoBusinessProcessInstanceId::contains).collect(Collectors.toList());
		    doneBusinessProcessInstanceId = businessProcessInstanceIdList.stream().filter(doneBusinessProcessInstanceId::contains).collect(Collectors.toList());

		    return new WorkflowCountStatics(doneBusinessProcessInstanceId.size(), todoBusinessProcessInstanceId.size());
	    }else{

		    // 分组的类型
		    HashMap<String, WorkflowCountStatics> workflowCountStaticsMap = new HashMap<>();
		    Set<String> queryFieldTypeSet = businessDataList.stream().map(t -> ReflectUtil.getFieldValue(t, StrUtil.toCamelCase(queryField)).toString()).collect(Collectors.toSet());
		    for(String queryFieldType : queryFieldTypeSet){

			    // 类型的工作流实例编号
			    List<Object> queryFieldTypBusinessDataList = businessDataList.stream().filter(t -> queryFieldType.equals(ReflectUtil.getFieldValue(t, StrUtil.toCamelCase(queryField)).toString())).collect(Collectors.toList());
			    Set<String> queryFieldTypeProcessInstanceIdSet = queryFieldTypBusinessDataList.stream().map(t -> ReflectUtil.getFieldValue(t, StrUtil.toCamelCase(workflowInstanceFieldName)).toString()).collect(Collectors.toSet());

			    // 待办、已办
			    Set<String> todoQueryFieldTypeBusinessProcessInstanceId = queryFieldTypeProcessInstanceIdSet.stream().filter(todoBusinessProcessInstanceId::contains).collect(Collectors.toSet());
			    Set<String> doneQueryFieldTypeBusinessProcessInstanceId = queryFieldTypeProcessInstanceIdSet.stream().filter(doneBusinessProcessInstanceId::contains).collect(Collectors.toSet());

			    workflowCountStaticsMap.put(queryFieldType, new WorkflowCountStatics(doneQueryFieldTypeBusinessProcessInstanceId.size(), todoQueryFieldTypeBusinessProcessInstanceId.size()));
		    }

		    return workflowCountStaticsMap;
	    }

    }

    private List<Object> getBusinessDataByWorkflowKey(String workflowKey, String workflowInstanceFieldName, String queryField, String queryFieldValue) {
        ServiceImpl businessService = workflowDefinitionAccessor.getBusinessService(workflowKey);

        String selectField = workflowInstanceFieldName;
        if(StringUtils.isNotBlank(queryField)){
	        selectField = String.format("%s, %s", workflowInstanceFieldName, queryField);
        }

        QueryWrapper<?> queryWrapper = (QueryWrapper<?>) new QueryWrapper().select(selectField).
	        eq(StringUtils.isNotBlank(queryFieldValue) && StringUtils.isNotBlank(queryFieldValue), queryField, queryFieldValue);
        List<Object> businessDataList = businessService.list(queryWrapper);
        if (CollectionUtils.isEmpty(businessDataList)) {
            return Collections.emptyList();
        }

	    return businessDataList;
    }

    @Override
    public void diagram(String workflowInstanceId, HttpServletResponse httpServletResponse) {
        // 获得当前活动的节点
        String processDefinitionId;
        Set<String> currIds = Collections.emptySet();

        // 如果流程已经结束，则得到结束节点
        if (this.isFinished(workflowInstanceId)) {
            HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(workflowInstanceId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        } else {
            // 如果流程没有结束，则取当前活动节点
            // 根据流程实例ID获得当前处于活动状态的ActivityId合集
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(workflowInstanceId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();

            currIds = runtimeService.createExecutionQuery().processInstanceId(pi.getId()).list().stream().map(Execution::getActivityId).collect(Collectors.toSet());
        }
        List<String> highLightedActivities = new ArrayList<>();

        // 获得活动的节点
        List<HistoricActivityInstance> highLightedActivityList = historyService.createHistoricActivityInstanceQuery().processInstanceId(workflowInstanceId).orderByHistoricActivityInstanceStartTime().asc().list();

        for (HistoricActivityInstance tempActivity : highLightedActivityList) {
            String activityId = tempActivity.getActivityId();
            highLightedActivities.add(activityId);
        }

        List<String> flows = new ArrayList<>();
        // 获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);

        CustomProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivities, flows, "宋体", "宋体", "宋体",
                null, 1.0, new Color[]{FlowableWorkflowConstants.COLOR_NORMAL, FlowableWorkflowConstants.COLOR_CURRENT}, currIds);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int length;
        try {
            out = httpServletResponse.getOutputStream();
            while ((length = in.read(buf)) != -1) {
                out.write(buf, 0, length);
            }
        } catch (IOException e) {
            log.error("操作异常", e);
        } finally {
            IoUtil.closeSilently(out);
            IoUtil.closeSilently(in);
        }
    }

    private boolean isFinished(String processInstanceId) {
        return historyService.createHistoricProcessInstanceQuery().finished().processInstanceId(processInstanceId).count() > 0;
    }

    private ArrayList<String> listTaskBusinessKey(List<Task> taskList) {
        Set<String> businessKeySet = new HashSet<>();
        Set<String> processInstanceIdSet = taskList.stream().map(TaskInfo::getProcessInstanceId).collect(Collectors.toSet());
        for (String processInstanceId : processInstanceIdSet) {
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            businessKeySet.add(processInstance.getBusinessKey());
        }
        return new ArrayList<>(businessKeySet);
    }

    private ArrayList<String> listHistoryTaskBusinessKey(List<HistoricTaskInstance> taskList) {
        Set<String> businessKeySet = new HashSet<>();
        Set<String> processInstanceIdSet = taskList.stream().map(TaskInfo::getProcessInstanceId).collect(Collectors.toSet());
        for (String processInstanceId : processInstanceIdSet) {
            HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            businessKeySet.add(processInstance.getBusinessKey());
        }
        return new ArrayList<>(businessKeySet);
    }

    private TaskQuery wrapperTaskQuery(Object userId, Object groupId, String workflowKey, String taskKey) {
        TaskQuery taskQuery = taskService.createTaskQuery();
        if (null != userId && StringUtils.isNotBlank(userId.toString())) {
            taskQuery.taskCandidateOrAssigned(userId.toString());
        }
        if (null != groupId && StringUtils.isNotBlank(groupId.toString())) {
            taskQuery.taskCandidateGroup(groupId.toString());
        }
        if (StringUtils.isNotBlank(workflowKey)) {
            taskQuery.processDefinitionKey(workflowKey);
        }
        if (StringUtils.isNotBlank(taskKey)) {
            taskQuery.taskDefinitionKey(taskKey);
        }
        return taskQuery;
    }

    private HistoricTaskInstanceQuery wrapperHistoryTaskQuery(String workflowKey, String taskKey, Object userId) {
        HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService
                .createHistoricTaskInstanceQuery().processDefinitionKey(workflowKey).finished();
        if (null != userId && StringUtils.isNotBlank(userId.toString())) {
            historicTaskInstanceQuery.taskInvolvedUser(userId.toString());
        }
        if (StringUtils.isNotBlank(taskKey)) {
            historicTaskInstanceQuery.taskId(taskKey);
        }
        return historicTaskInstanceQuery;
    }

}
